home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * FREXX PROGRAMMING LANGUAGE *
- ******************************************************************************
-
- script.c
-
- The main routine of the language. Handles all keywords, {'s and }'s.
-
- *****************************************************************************/
-
- /************************************************************************
- * *
- * fpl.library - A shared library interpreting script langauge. *
- * Copyright (C) 1992-1994 FrexxWare *
- * Author: Daniel Stenberg *
- * *
- * This program is free software; you may redistribute for non *
- * commercial purposes only. Commercial programs must have a written *
- * permission from the author to use FPL. FPL is *NOT* public domain! *
- * Any provided source code is only for reference and for assurance *
- * that users should be able to compile FPL on any operating system *
- * he/she wants to use it in! *
- * *
- * You may not change, resource, patch files or in any way reverse *
- * engineer anything in the FPL package. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
- * *
- * Daniel Stenberg *
- * Ankdammsgatan 36, 4tr *
- * S-171 43 Solna *
- * Sweden *
- * *
- * FidoNet 2:201/328 email:dast@sth.frontec.se *
- * *
- ************************************************************************/
-
- #ifdef AMIGA
- #include <exec/types.h>
- #include <proto/exec.h>
- #include <libraries/dos.h>
- #include <proto/dos.h>
-
- #include <exec/libraries.h>
- #include <dos.h>
-
- #elif defined(UNIX)
- #include <sys/types.h>
- #endif
-
- #include <stdio.h>
- #include <string.h>
- #include "script.h"
-
- #ifdef DEBUG
- long mem=0;
- long maxmem=0;
- #endif
-
- static ReturnCode INLINE AddProgram(struct Data *, struct Program **,
- char *, long, char *);
- static char REGARGS CheckIt(struct Data *, struct Expr *, short, ReturnCode *);
- static ReturnCode INLINE Declare(struct Expr *, struct Data *,
- struct Identifier *, long);
- static ReturnCode INLINE Eatcomment(struct Data *);
- static ReturnCode Go(struct Data *, struct Expr *val);
- static ReturnCode REGARGS Loop(struct Data *, struct Condition *, short, char *);
- static ReturnCode INLINE Resize(struct Data *, struct Expr *, char);
- static ReturnCode REGARGS SkipStatement(struct Data *);
- static ReturnCode REGARGS StoreGlobals(struct Data *, char type);
- static ReturnCode REGARGS Run(struct Data *, char *, char *, long, unsigned long *);
- static ReturnCode INLINE Switch(struct Data *, struct Expr *, short,
- struct Condition *);
- /*
- * Global static string arrays for everywhere access:
- */
-
- const char type[256] = { /* Character type codes Hex */
- END, 000, 000, 000, 000, 000, 000, 000, /* 00 */
- 000, SPA, SPA, 000, 000, SPA, 000, 000, /* 08 */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 18 */
- SPA, 000, 000, 000, 000, 000, 000, 000, /* 20 !"#$%&' */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 28 ()*+,-./ */
- DIG|HEX, DIG|HEX, DIG|HEX, DIG|HEX, /* 30 0123 */
- DIG|HEX, DIG|HEX, DIG|HEX, DIG|HEX, /* 34 4567 */
- DIG, DIG, 000, 000, 000, 000, 000, 000, /* 38 89:;<=>? */
- 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */
- LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */
- LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */
- LET, LET, LET, 000, 000, 000, 000, LET, /* 58 XYZ[\]^_ */
- 000, LET|HEX, LET|HEX, LET|HEX, /* 60 `abc */
- LET|HEX, LET|HEX, LET|HEX, LET, /* 64 defg */
- LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */
- LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */
- LET, LET, LET, 000, 000, 000, 000, 000, /* 78 xyz{|}~ */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */
- };
-
-
- /***************************************************************************
- *
- * fplExecuteFile()
- *
- * Executes the specified file as an FPL program.
- *
- ******/
-
- ReturnCode PREFIX fplExecuteFile(AREG(0) struct Data *scr,
- AREG(1) char *filename,
- AREG(2) unsigned long *tags)
- {
- return(Run(scr, filename, NULL, 1, tags));
- }
-
- /**********************************************************************
- *
- * fplExecuteScript()
- *
- * Frontend to Run().
- *
- * The error code is returned to daddy...
- *
- ******/
-
- ReturnCode PREFIX fplExecuteScript(AREG(0) struct Data *scr, /* nice struct */
- AREG(1) char **program, /* program array */
- DREG(1) long lines, /* number of lines */
- AREG(2) unsigned long *tags)
- {
- return(Run(scr, NULL, *program, lines, tags));
- }
-
-
- /**************************************************************************
- *
- * ReadFile()
- *
- * Reads the specified file into memory, stores the pointer to the memory
- * area in the pointer `program' points to, and the size of the memory area
- * in the integer `size' points to. I decided to use a different way on Amiga
- * to increase performance a lot.
- *
- * This function first checks the size of the file it's about to fetch
- * and then reads the entire file at once in one continuos memory area.
- *
- * Returns the proper return code. If anything goes wrong, there won't be
- * *ANY* program to look at (the pointer will be NULL, but the size will most
- * probably still be correct which means a non-zero value). If this function
- * fails it takes care of freeing the program memory by itself. You only have
- * to free that memory if this functions reports success.
- *
- ********/
-
- ReturnCode
- ReadFile(void *fpl,
- char *filename,
- struct Program *prog)
- {
- struct Data *scr=(struct Data *)fpl;
- #ifdef AMIGA /* Amiga version. */
- struct FileInfoBlock fileinfo;
- struct FileLock *lock;
- struct FileHandle *fileread;
-
- struct MyLibrary *lib = (struct MyLibrary *)getreg(REG_A6);
- struct Library *DOSBase = lib->ml_DosBase;
- #elif defined(UNIX)
- FILE *stream;
- #endif
- ReturnCode ret=FPL_OK;
- #ifdef AMIGA
-
- /* Lock on source file to get file length! */
- if (lock=(struct FileLock *)Lock((UBYTE *)filename, ACCESS_READ)) {
- if (Examine((BPTR)lock, &fileinfo))
- prog->size=fileinfo.fib_Size+1; /* Add one for a terminating zero! */
- else
- ret=FPLERR_OPEN_ERROR; /* something went wrong */
- if(!(scr->flags&FPLDATA_LOCKUSED)) {
- UnLock((BPTR)lock); /* release the lock of the file */
- prog->lock=NULL; /* no lock */
- } else
- prog->lock=(void *)lock; /* store lock! */
- } else
- ret=FPLERR_OPEN_ERROR; /* we couldn't lock on the file */
- #elif defined(UNIX)
- if (!(stream = fopen(filename, "r")))
- ret=FPLERR_OPEN_ERROR;
- else {
- if(fseek(stream, 0, 2)) {
- fclose(stream);
- ret=FPLERR_OPEN_ERROR;
- } else {
- prog->size=ftell(stream)+1;
- fseek(stream, 0, 0);
- }
- }
- #endif
- if(ret)
- return(ret);
-
- /* Open file for reading. */
- #ifdef AMIGA
- /* We could use OpenFromLock() here, but it's a V36+ function! */
- fileread=(struct FileHandle *)Open((UBYTE *)filename, MODE_OLDFILE);
- #elif defined(UNIX)
- /* file is already opened! */
- #endif
- prog->program=(char *)MALLOC(prog->size); /* Allocate memory for program. */
- if(!prog->program) /* if we didn't get the requested memory: */
- ret=FPLERR_OUT_OF_MEMORY;
- #ifdef AMIGA
- else if(Read((BPTR)fileread, prog->program, (LONG)prog->size)<0) /* get entire file */
- #elif defined(UNIX)
- else if(!fread(prog->program, 1, prog->size, stream))
- #endif
- /* if we couldn't Read() the file: */
- ret=FPLERR_OPEN_ERROR;
- else
- (prog->program)[prog->size-1]='\0'; /* add the terminating zero byte. */
- #ifdef AMIGA
- Close((BPTR)fileread); /* close file */
- #elif defined(UNIX)
- fclose(stream); /* close the stream */
- #endif
- /* only if error and we could allocate the proper memory */
- if(ret && prog->program) {
- FREE(prog->program); /* free the, for the program allocated, memory */
- }
- return(ret); /* get back to parent */
- }
-
- /**********************************************************************
- *
- * AddProgram();
- *
- * Adds a program to FPL's internal lists of program files.
- *
- ****/
-
- static ReturnCode INLINE AddProgram(struct Data *scr,
- struct Program **get,
- char *program,
- long lines,
- char *name)
- {
- struct Program *next, *prog=NULL;
- ReturnCode ret;
- if(name) {
- /*
- * Name was given. Search through the internals to see if
- * we have this file cached already!
- */
- prog=scr->programs;
- while(prog) {
- if(!strcmp(prog->name, name))
- break;
- prog=prog->next;
- }
- }
- if(!prog) {
- GETMEMA(prog, sizeof(struct Program));
- memset(prog, 0, sizeof(struct Program));
- #ifdef DEBUG
- CheckMem(scr, prog);
- #endif
- next=scr->programs;
- prog->next=next;
- prog->program=program;
- prog->lines=lines;
- prog->startprg=1;
- prog->virprg=1;
- if(name) {
- STRDUPA(prog->name, name);
- }
- scr->programs=prog;
- } else {
- /*
- * The program already exists.
- */
- CALL(LeaveProgram(scr, scr->prog));
- CALL(GetProgram(scr, prog));
- }
- scr->prog=prog;
- *get=prog;
- return(FPL_OK);
- }
-
- /**********************************************************************
- *
- * DelProgram()
- *
- * Deletes a specifed program from memory. If NULL is specified where
- * the program struct is supposed, all programs are removed! (Amiga
- * version *have* to do that to UnLock() all files that might be locked
- * when using the FPLTAG_LOCKUSED!
- *
- *******/
-
- ReturnCode DelProgram(struct Data *scr,
- struct Program *del)
- {
- struct Program *prog=scr->programs, *prev=NULL;
- while(prog) {
- if(!del || prog==del) {
- if(prev)
- prev->next=prog->next;
- else
- scr->programs=prog->next;
- if(scr->prog==del)
- scr->prog=scr->prog->next;
- #ifdef AMIGA
- if(prog->lock)
- UnLock((BPTR)prog->lock); /* unlock the program if it was locked before! */
- #endif
- prev=prog->next;
- if(prog->name)
- FREEA(prog->name);
- FREEA(prog);
- if(!del) {
- prog=prev;
- prev=NULL;
- } else {
- if(del)
- break;
- }
- } else {
- prev=prog;
- prog=prog->next;
- }
- }
- return(FPL_OK);
- }
-
- /**********************************************************************
- *
- * Run()
- *
- *****/
-
- static ReturnCode REGARGS
- Run(struct Data *scr,
- char *filename,
- char *program,
- long lines,
- unsigned long *tags)
- {
- ReturnCode ret, end;
- struct Expr *val;
- unsigned long *tag=tags;
- char storeglobals; /* DEFAULT: fplInit() value! */
- struct Program *thisprog, *prog;
- struct Store *store;
- struct Local *glob;
-
- #ifdef DEBUG
- long memory=mem;
- #endif
-
- if(!scr)
- /* misbehaviour */
- return(FPLERR_ILLEGAL_ANCHOR);
-
- if(scr->runs) {
- /* is this a nested call? */
- LeaveProgram(scr, scr->prog);
- GETMEM(store, sizeof(struct Store));
- memcpy(store, &scr->text, sizeof(struct Store));
- } else
- scr->msg = NULL; /* We start with an empty message queue! */
-
- CALL(AddProgram(scr, &prog, program, lines, filename));
-
- if(!prog->program && filename) {
- /*
- * It didn't already exist.
- */
- CALL(ReadFile(scr, filename, prog)); /* get file */
- prog->flags|=PR_FILENAMEFLUSH;
- } else if(!filename)
- prog->flags=PR_USERSUPPLIED;
-
- CALL(GetProgram(scr, prog)); /* lock it for our use! */
-
- thisprog=scr->prog;
- if(scr->flags&FPLDATA_CACHEALLFILES) {
- thisprog->flags|=PR_CACHEFILE;
- if(scr->flags&FPLDATA_CACHEEXPORTS)
- thisprog->flags|=PR_CACHEEXPORTS;
- } else
- thisprog->flags&=~PR_CACHEFILE;
-
- thisprog->openings++;
-
- scr->prg=thisprog->startprg; /* starting line number */
- scr->text=(&thisprog->program)[thisprog->startprg-1]+
- thisprog->startcol; /* execute point */
-
- scr->ret=FPL_OK; /* return code reset */
- scr->virprg=1; /* starting at virtual line 1 */
- scr->level=0; /* level counter */
- scr->varlevel=0; /* variable level */
- scr->strret=FALSE; /* we don't want no string back! */
- scr->interpret=NULL; /* no interpret tag as default */
- scr->locals=NULL; /* local symbol list */
- scr->globals=NULL; /* global symbol list */
- scr->FPLret=0; /* initialize return code value */
- scr->string_return=NULL; /* no string returns allowed */
- #ifdef COMPILE_AVAIL
- scr->compiling=0; /* no compiling */
- #endif
-
- while(tag && *tag) {
- switch(*tag++) {
- #ifdef COMPILE_AVAIL
- case FPLTAG_COMPILE: /* future implementation */
- scr->compiling = (char)*tag;
- break;
- #endif
- case FPLTAG_STRING_RETURN:
- scr->string_return = (char **)*tag;
- scr->strret=TRUE; /* enable return string */
- break;
-
- case FPLTAG_INTERPRET:
- scr->interpret=(char *)*tag;
- break;
-
- case FPLTAG_STARTPOINT:
- scr->text=(char *)*tag;
- break;
- case FPLTAG_STARTLINE:
- scr->prg=(long)*tag;
- break;
- case FPLTAG_USERDATA:
- scr->userdata=(void *)*tag;
- break;
- case FPLTAG_CACHEFILE:
- if(*tag) {
- thisprog->flags|=PR_CACHEFILE;
- if(*tag=FPLCACHE_EXPORTS)
- thisprog->flags|=PR_CACHEEXPORTS;
- } else
- thisprog->flags&=~PR_CACHEFILE;
- break;
- case FPLTAG_PROGNAME:
- prog=scr->programs;
- while(prog) {
- if(!strcmp(prog->name, (char *)*tag))
- break;
- prog=prog->next;
- }
- if(!prog) {
- /*
- * The program was not found, then set/rename the
- * current program to this name!
- */
- if(thisprog->name) {
- FREEA(thisprog->name);
- }
- STRDUPA(thisprog->name, *tag);
- } else {
- /*
- * We found another progam with that name. Execute that
- * instead of this!
- */
- DelProgram(scr, thisprog);
- thisprog=prog;
- }
- break;
- case FPLTAG_FILENAMEGET:
- if(*tag)
- thisprog->flags|=PR_FILENAMEFLUSH;
- else
- thisprog->flags&=~PR_FILENAMEFLUSH;
- break;
- }
- tag++;
- }
-
- if(!thisprog->name || scr->compiling) {
- /* If no name has been given, do not store any global symbols from it! */
- STRDUPA(thisprog->name, FPLTEXT_UNKNOWN_PROGRAM);
- storeglobals=FALSE;
- thisprog->flags&=~(PR_CACHEFILE|PR_CACHEEXPORTS);
- } else
- storeglobals = thisprog->flags&(PR_CACHEFILE|PR_CACHEEXPORTS);
-
- scr->virfile=thisprog->name; /* starting with this file */
-
- GETMEM(val, sizeof(struct Expr));
- end=Go(scr, val);
- if(end<=FPL_EXIT_OK &&
- scr->string_return &&
- (val->flags&(FPL_STRING|FPL_RETURN)) == (FPL_STRING|FPL_RETURN)) {
- /*
- * No error and
- * we accept string returns and
- * we have a returned string to deal with and
- * there was a final "return" or "exit" keyword.
- */
-
- /* assign the pointer */
- if(val->val.str) {
- *scr->string_return = val->val.str->string;
-
- /* make it a "static" allocation */
- SwapMem(scr, val->val.str, MALLOC_STATIC);
- }
- else
- *scr->string_return = NULL;
-
- }
- FREE(val);
-
- if(end>FPL_EXIT_OK) {
- struct fplArgument pass={
- NULL, FPL_GENERAL_ERROR, NULL, 0};
- void *array[1];
- pass.key=(void *)scr;
- array[0] = (void *)end;
- pass.argv= array;
-
- /* new argv assigning for OS/2 compliance! */
- InterfaceCall(scr, &pass, scr->function);
- }
-
- thisprog->column=scr->text-(&thisprog->program)[scr->prg-1]+1;
- scr->virfile=NULL; /* most likely to not point to anything decent
- anyway! */
-
- /*
- * Go through the ENTIRE locals list and delete all. Otherwise they will
- * ruin the symbol table.
- */
-
- while(scr->locals)
- DelLocalVar(scr, &scr->locals);
-
- thisprog->openings--;
- CALL(LeaveProgram(scr, thisprog));
-
- /*
- * If the option to cache only programs exporting symbols is turned on,
- * then we must check if any of the globals are exported before caching!
- */
-
- if(end<=FPL_EXIT_OK && (storeglobals & PR_CACHEEXPORTS)) {
- glob = scr->globals;
-
- while(glob) {
- /* Traverse all global symbols */
-
- if(glob->ident->flags&FPL_EXPORT_SYMBOL)
- /* if we found an exported symbol, get out of loop */
- break;
-
- glob=glob->next; /* goto next global */
- }
-
- if(!glob)
- /* no exported symbols were found! */
- storeglobals = FALSE; /* do not cache this file! */
- }
-
- if(end<=FPL_EXIT_OK && storeglobals) {
- /* is it changed and we should store the info and not compiling */
-
- if(!(thisprog->flags&PR_GLOBALSTORED)) {
-
- if(scr->globals) {
-
- /* Store all global symbols!!! */
- CALL(StoreGlobals(scr, MALLOC_STATIC));
-
- if(thisprog->flags&PR_CACHEFILE && !(thisprog->flags&PR_USERSUPPLIED))
- SwapMem(scr, thisprog->program, MALLOC_STATIC);
- /* else
- The memory is allocated by the user or not to be cached! */
- thisprog->flags|=PR_GLOBALSTORED;
- } else
- DelProgram(scr, thisprog); /* this also removes the Lock() */
- }
- } else {
- /*
- * We must delete the global symbol lists
- * properly and not just free the memory. Otherwise we might free memory
- * used in the middle of the list we intend to save for next run!
- */
- if(!thisprog->openings) {
- /* If not in use */
- if(scr->globals)
- /* There is some global symbols to delete! */
- DelLocalVar(scr, &scr->globals);
-
- /* Delete this program from memory! */
- DelProgram(scr, thisprog); /* this also removes the Lock() */
- }
- }
-
- tag=tags;
- while(tag && *tag) {
- switch(*tag++) {
- case FPLTAG_FILEGLOBALS:
- /* case FPLTAG_ISCACHED: */
- *(long *)*tag=(long)scr->globals;
- break;
- }
- tag++;
- }
-
- if(!--scr->runs) { /* not running any more! */
- if(end>FPL_EXIT_OK) {
- FREEALL(); /* frees all ALLOC_DYNAMIC */
- }
- } else {
- memcpy(&scr->text, store, sizeof(struct Store));
- GetProgram(scr, scr->prog);
- FREE(store);
- }
-
- return(end==FPL_EXIT_OK?FPL_OK:end);
- }
-
- /**********************************************************************
- *
- * Go();
- *
- * This is an own function to make the stack usage in this particular
- * function very small. Then we don't have to copy more than 10-20 bytes
- * of the old stack when swapping to the new in the amiga version of the
- * library!
- *
- ******/
-
- static ReturnCode Go(struct Data *scr, struct Expr *val)
- {
- ReturnCode ret;
- #if defined(AMIGA) && defined(SHARED)
- /* The function call below is a assembler routine that allocates a new
- stack to use in the library! */
- if(!scr->runs++) {
- ret=InitStack(scr, val,
- SCR_BRACE| /* to make it loop and enable declarations */
- SCR_FUNCTION| /* return on return() */
- SCR_GLOBAL, /* global symbol declarations enabled */
- NULL);
- EndStack(scr, scr->stack_max);
- } else {
- ret=Script(scr, val,
- SCR_BRACE| /* to make it loop and enable declarations */
- SCR_FUNCTION| /* return on return() */
- SCR_GLOBAL, /* global symbol declarations enabled */
- NULL);
- }
- #else /* Not Amiga, Not shared! */
- scr->runs++;
- ret=Script(scr, val,
- SCR_BRACE| /* to make it loop and enable declarations */
- SCR_FUNCTION| /* return on return() */
- SCR_GLOBAL, /* global symbol declarations enabled */
- NULL);
- #endif
- return(ret);
- }
-
-
- static ReturnCode REGARGS
- StoreGlobals(struct Data *scr,
- char type)
- {
- struct Local *local, *prev=NULL;
- struct Identifier *ident;
- struct fplVariable *var;
-
- if(scr->prog->running>1)
- /*
- * It's enough if we commit this only on the ground level exit!
- */
- return(FPL_OK);
-
- local=scr->globals;
- while(local) {
- ident=local->ident;
- if(ident->flags&FPL_VARIABLE) {
- SwapMem(scr, local, type); /* preserve the chain! */
- SwapMem(scr, ident, type); /* structure */
- SwapMem(scr, ident->name, type); /* name */
- var=&ident->data.variable;
-
- SwapMem(scr, var->var.val32, type); /* variable area */
-
- if(!var->num && ident->flags&FPL_STRING_VARIABLE && var->var.str)
- /* no array but string variable */
- SwapMem(scr, var->var.str, type); /* string */
- else if(var->num) {
- /* array */
- SwapMem(scr, var->dims, type); /* dim info */
- if(ident->flags&FPL_STRING_VARIABLE) {
- int i;
- for(i=0; i<var->size; i++) {
- /* Take one pointer at a time */
- if(var->var.str[i])
- /* if the value is non-zero, it contains the allocated length
- of the corresponding char pointer in the ->array->vars
- array! */
- SwapMem(scr, var->var.str[i], type);
- }
- SwapMem(scr, var->var.str, type);
- }
- }
- } else if(ident->flags&FPL_FUNCTION) {
- SwapMem(scr, local, type); /* preserve the chain! */
- SwapMem(scr, ident, type); /* structure */
- SwapMem(scr, ident->name, type); /* name */
- SwapMem(scr, ident->data.inside.format, type); /* parameter string */
- }
- prev=local;
- local=local->next;
- }
- if(prev) {
- prev->next=scr->usersym; /* link in front of our previous list! */
- scr->usersym=scr->globals;
- }
- scr->globals=NULL;
- return(FPL_OK);
- }
-
- /**************************************************************************
- *
- * int Script(struct Data *);
- *
- * Interprets an FPL program, very recursive. Returns progress in an integer,
- * and the FPL program result code in the int scr->ret.
- * USE AS FEW VARIABLES AS POSSIBLE to spare stack usage!
- *
- **********/
-
- ReturnCode
- Script(struct Data *scr, /* big FPL structure */
- struct Expr *val, /* result structure */
- short control, /* control byte */
- struct Condition *con)
- {
- char declare=control&SCR_BRACE?1:0; /* declaration allowed? */
- ReturnCode ret; /* return value variable */
- struct Condition *con2; /* recursive check information! */
- char brace=0; /* general TRUE/FALSE variable */
- char *text; /* position storage variable */
- long prg; /* position storage variable */
- long levels=scr->level; /* previous level spectra */
- struct Identifier *ident; /* used when checking keywords */
- long virprg=scr->virprg;
- char *virfile=scr->virfile;
- char done=FALSE; /* TRUE when exiting */
- struct fplArgument *pass;
- #if defined(AMIGA) && defined(SHARED)
- if(ret=CheckStack(scr, scr->stack_limit, FPLSTACK_MINIMUM)) {
- if(ret==1)
- return(FPLERR_OUT_OF_MEMORY);
- else
- return(FPLERR_OUT_OF_STACK);
- }
- #endif
-
- if(control&(SCR_BRACE|SCR_FUNCTION)) {
- /*
- * New symbol declaration level!
- */
- scr->varlevel++;
- CALL(AddLevel(scr));
- }
-
- if(control&SCR_FUNCTION)
- scr->level=0; /* number of levels to look for variables */
- else if(control&SCR_BRACE)
- scr->level++;
-
- while(!done) {
- if(ret=Eat(scr)) {
- if(scr->varlevel==1 && ret==FPLERR_UNEXPECTED_END)
- /* It's OK! */
- ret=FPL_OK;
- if(scr->compiling)
- COMPILE(COMP_END_OF_PROGRAM);
- break;
- }
-
- /* call the interval function */
- if(scr->interfunc) {
- if(scr->data=InterfaceCall(scr, scr->userdata, scr->interfunc))
- CALL(Warn(scr, FPLERR_PROGRAM_STOPPED)); /* >warning< */
- }
-
- switch(*scr->text) {
- case CHAR_OPEN_BRACE: /* open brace */
- scr->text++;
- if(scr->compiling)
- COMPILE(COMP_START_OF_BLOCK);
- CALL(Script(scr, val, SCR_NORMAL|SCR_BRACE, con));
- if(CheckIt(scr, val, control, &ret)) {
- CleanUp(scr, control, levels);
- return(ret);
- }
- break;
-
- case CHAR_CLOSE_BRACE:
- if(control&SCR_LOOP) {
- if(control&SCR_BRACE) {
- DelLocalVar(scr, &scr->locals); /* delete all local declarations */
- scr->varlevel--; /* previous variable level */
- scr->level--; /* previous level spectra */
- }
- CALL(Loop(scr, con, control, &brace));
- if(!scr->compiling) {
- if(brace) {
- /* Yes! We should loop! */
- if(control&SCR_BRACE) {
- /* bring back the proper values */
- scr->varlevel++;
- scr->level++;
- AddLevel(scr); /* restart this level! */
- declare=TRUE;
- }
- scr->virprg=virprg;
- scr->virfile=virfile;
- continue;
- }
- } else
- scr->text++; /* pass the brace! */
- val->flags=0;
- } else {
- scr->text++;
- val->flags=FPL_BRACE;
- CleanUp(scr, control, levels);
- }
- if(scr->compiling) {
- COMPILE(COMP_END_OF_BLOCK);
- if(scr->varlevel == 0) {
- /*
- * This is the end of the ground function. We choose to continue
- * anyway to scan the entire file!
- * Then functions can again appear in the code, so we activate the
- * 'declare' flag again!
- */
- declare = TRUE;
- break;
- }
- }
- return(FPL_OK); /* return to calling function */
-
- case CHAR_SEMICOLON:
- scr->text++;
- break;
-
- default:
- /*
- * Time to parse the statement!
- */
-
- text=scr->text; /* store current position */
- prg=scr->prg;
- CALL(Getword(scr->buf, scr)); /* get next word */
-
- GetIdentifier(scr, scr->buf, &ident);
-
- if(ident && control&SCR_GLOBAL && declare) {
- /* still on ground level and declaration allowed */
- if(!(ident->flags&FPL_KEYWORD_DECLARE)) {
- /*
- * We move the pointer for the execution start position to
- * this position.
- */
- scr->prog->startcol=text-(&scr->prog->program)[prg-1];
- scr->prog->startprg=prg;
- scr->prog->virprg=scr->virprg;
- scr->prog->virfile=scr->virfile;
-
- if(scr->compiling)
- COMPILE(COMP_START_OF_CODE);
-
- /*
- * This is the end of the declaration phase. Now, let's
- * check for that FPLTAG_INTERPRET tag to see if we should
- * have a little fun or simply continue!
- */
- if(scr->interpret) {
- done = TRUE;
- continue;
- }
- }
- }
- if(ident && ident->flags&FPL_KEYWORD) {
- if(ident->flags&FPL_KEYWORD_DECLARE) {
- if(!declare) {
- CALL(Warn(scr, FPLERR_ILLEGAL_DECLARE)); /* WARNING! */
- /* declare it anyway!!! */
- }
- CALL(Declare(val, scr, ident, control&SCR_GLOBAL?CON_DECLGLOB:0));
-
- } else {
- if(scr->compiling)
- COMPILESYMBOL(scr->buf);
-
- switch(ident->data.external.ID) {
- case CMD_SWITCH:
- CALL(Switch(scr, val, control, con));
- if(CheckIt(scr, val, control, &ret)) {
- CleanUp(scr, control, levels);
- return(ret);
- }
- break;
-
- case CMD_CASE: /* 'case' */
- if(!control&SCR_SWITCH)
- return FPLERR_ILLEGAL_STATEMENT; /* 'case' not within switch! */
- /*
- * This word can only be found if (control&SCR_SWITCH), and then
- * we must just skip the "case XX:" text and continue.
- */
- CALL(GetEnd(scr, CHAR_COLON, 255, FALSE)); /* find colon! */
- if(val->flags&FPL_STRING && !(val->flags&FPL_NOFREE) && val->val.str)
- /* If there was a string return, it should be freed and the
- string really held a string! */
- FREE(val->val.str);
- /* Check the colon */
- if(scr->text[0]!=CHAR_COLON) {
- CALL(Warn(scr, FPLERR_MISSING_COLON)); /* missing colon! */
- } else
- scr->text++;
- break;
-
- case CMD_DEFAULT: /* 'default' */
- if(!control&SCR_SWITCH)
- return FPLERR_ILLEGAL_STATEMENT; /* 'default' not within switch! */
- /*
- * This word can only be found if (control&SCR_SWITCH), and then
- * we must just skip the "default:" text and continue.
- */
- if(scr->text[0]!=CHAR_COLON) {
- CALL(GetEnd(scr, CHAR_COLON, 255, FALSE));
- } else
- scr->text++;
- break;
-
- case CMD_TYPEDEF:
- CALL(Getword(scr->buf, scr));
- CALL(GetIdentifier(scr, scr->buf, &ident));
- if(!ret &&
- (ident->data.external.ID==CMD_INT ||
- ident->data.external.ID==CMD_STRING)) {
- if(scr->compiling)
- COMPILESYMBOL(scr->buf);
- CALL(Getword(scr->buf, scr));
- if(scr->compiling)
- COMPILESYMBOL(scr->buf);
- text=(void *)ident;
- GETMEM(ident, sizeof(struct Identifier));
- *ident=*(struct Identifier *)text; /* copy entire structure! */
- GETMEM(ident->name, strlen(scr->buf)+1);
- strcpy(ident->name, scr->buf);
- ident->flags&=~FPL_INTERNAL_FUNCTION; /* no longer any internal
- declarator symbol! */
- CALL(AddVar(scr, ident, &scr->locals));
- } else {
- CALL(Warn(scr, FPLERR_IDENTIFIER_NOT_FOUND));
- /* then just skip this statement! */
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE));
- }
- break;
- case CMD_RETURN:
- case CMD_EXIT:
- Eat(scr);
- if(*scr->text!=CHAR_SEMICOLON) { /* no return XÂ */
- brace=*scr->text==CHAR_OPEN_PAREN; /* not required! */
- scr->text+=brace;
-
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
-
- /*
- * If return()ing from a function when scr->strret is TRUE,
- * return a string.
- */
- if((scr->strret && ident->data.external.ID==CMD_RETURN) ||
- (scr->string_return && ident->data.external.ID==CMD_EXIT)) {
- CALL(Expression(val, scr, CON_NORMAL, NULL));
- if(!(val->flags&FPL_STRING)) {
- /* that wasn't a string! */
- CALL(Warn(scr, FPLERR_ILLEGAL_PARAMETER));
- } else {
- /* It was a string! */
- if(val->flags&FPL_NOFREE) {
- /*
- * We're only refering to another string! We can't
- * allow that since that string might be a local
- * variable, and all such are about to be deleted now!
- */
- struct fplStr *string=NULL;
- GETMEM(string, val->val.str->len+sizeof(struct fplStr));
- memcpy(string,
- val->val.str,
- val->val.str->len+sizeof(struct fplStr));
- string->alloc=val->val.str->len;
- val->val.str=string;
- val->flags&=~FPL_NOFREE;
- }
- }
-
- } else {
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
- }
- if(scr->compiling)
- COMPILE(COMP_END_OF_EXPR);
- if(brace)
- if(*scr->text!=CHAR_CLOSE_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
- /* continue */
- } else
- scr->text++;
- } else {
- val->val.val=0;
- val->flags=0;
- }
- scr->FPLret=val->val.val; /* set return code! */
- if(ident->data.external.ID==CMD_RETURN) {
- ret=FPL_OK;
- } else
- ret=FPL_EXIT_OK; /* This will make us return through it all! */
-
- val->flags|=FPL_RETURN; /* inform calling function */
-
- if(scr->compiling)
- /* compiling, no function actually does anything! */
- break;
- CleanUp(scr, control, levels);
- return(ret);
- case CMD_IF: /* if() */
- case CMD_WHILE: /* while() */
- Eat(scr);
-
- /*********************
-
- PARSE CONDITION
-
- *******************/
-
-
- if(*scr->text!=CHAR_OPEN_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
- /* please, go on! */
- } else
- scr->text++;
-
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
-
- GETMEM(con2, sizeof(struct Condition));
-
- /* save check position! */
- con2->check=scr->text;
- con2->checkl=scr->prg;
-
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
- if(*scr->text!=CHAR_CLOSE_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES)); /* >warning< */
- /* continue */
- } else
- scr->text++;
-
- if(scr->compiling)
- COMPILE(COMP_END_OF_EXPR);
-
- if(val->val.val || scr->compiling) {
- /********************
-
- PARSE STATMENT
-
- ******************/
-
- Eat(scr);
- scr->text+=(brace=*scr->text==CHAR_OPEN_BRACE);
- con2->bracetext=scr->text;
- con2->braceprg=scr->prg;
- if(scr->compiling)
- COMPILE(COMP_START_OF_BLOCK);
- CALL(Script(scr, val,
- (brace?SCR_BRACE:0)|
- (ident->data.external.ID==CMD_WHILE?SCR_WHILE:SCR_IF),
- con2));
- if(CheckIt(scr, val, control, &ret)) {
- FREE(con2);
- CleanUp(scr, control, levels);
- return(ret);
- }
- brace=TRUE;
- } else {
- /********************
-
- SKIP STATEMENT
-
- ******************/
-
- CALL(SkipStatement(scr));
- brace=FALSE;
- }
-
- text=scr->text;
- prg=scr->prg;
-
- Getword(scr->buf, scr);
-
- if(!strcmp("else", scr->buf) && brace && !scr->compiling) {
- /********************
-
- SKIP STATEMENT
-
- ******************/
-
- CALL(SkipStatement(scr));
- } else if(!strcmp("else", scr->buf) && (!brace || scr->compiling)) {
- /********************
-
- PARSE STATMENT
-
- ******************/
-
- if(scr->compiling)
- COMPILESYMBOL("else");
- Eat(scr);
- scr->text+=(brace=*scr->text==CHAR_OPEN_BRACE);
- con2->bracetext=scr->text;
- con2->braceprg=scr->prg;
- if(scr->compiling)
- COMPILE(COMP_START_OF_BLOCK);
- CALL(Script(scr, val, (brace?SCR_BRACE:0), con2));
- if(CheckIt(scr, val, control, &ret)) {
- FREE(con2);
- CleanUp(scr, control, levels);
- return(ret);
- }
- } else {
- scr->text=text;
- scr->prg=prg;
- }
- FREE(con2);
- break;
- case CMD_BREAK:
- val->val.val=1; /* default is break 1 */
- Eat(scr);
- /*
- * Check if break out of several statements.
- */
- if(*scr->text!=CHAR_SEMICOLON) {
- /* Get the result of the expression. */
- brace=*scr->text==CHAR_OPEN_PAREN;
- scr->text+=brace;
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
- if(brace)
- if(*scr->text!=CHAR_CLOSE_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
- } else
- scr->text++;
- else if(val->val.val<0) {
- CALL(Warn(scr, FPLERR_ILLEGAL_BREAK));
- val->val.val=1; /* reset! */
- }
- }
- /*
- * Go to end of statement!!! If this was started without
- * SCR_BRACE set, we're already at the end of the statement!
- */
-
- if(scr->compiling) {
- /* When compiling, do no "real" break! */
- scr->text++;
- break;
- }
- if(control&SCR_BRACE)
- CALL(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, FALSE));
- if(control&SCR_DO)
- /* if it was inside a do statement, pass the ending `while' */
- CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE));
- val->flags|=FPL_BREAK;
- if(control&(SCR_LOOP|SCR_SWITCH))
- if(!--val->val.val)
- val->flags&=~FPL_BREAK; /* only this break! */
- CleanUp(scr, control, levels);
- return(FPL_OK);
- case CMD_CONTINUE:
- if(*scr->text!=CHAR_SEMICOLON) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON)); /* >warning< */
- } else
- scr->text++;
- if(scr->compiling)
- break; /* just continue on the next position! */
- if(control&SCR_LOOP) {
- /* loop! */
- if(control&SCR_BRACE && !scr->compiling) {
- DelLocalVar(scr, &scr->locals); /* delete all locals */
- scr->varlevel--; /* previous variable level */
- scr->level--; /* previous level spectra */
- }
- CALL(Loop(scr, con, control, &brace));
- if(!brace) {
- /*
- * The result of the condition check was FALSE. Move to the end
- * of the block and continue execution there!
- */
-
- if(control&SCR_BRACE) {
- /* braces */
- CALL(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, FALSE));
- } else {
- /* no braces! */
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE));
- }
- val->flags=0;
- } else {
- if(control&SCR_BRACE) {
- /* bring back the proper values */
- scr->varlevel++;
- scr->level++;
- AddLevel(scr); /* restart this level! */
- declare=TRUE;
- }
- scr->virprg=virprg;
- scr->virfile=virfile;
- continue;
- }
- } else {
- /* it's no looping statement! */
- val->flags=FPL_CONTINUE;
- CleanUp(scr, control, levels);
- }
- return(FPL_OK);
- case CMD_DO:
- CALL(Eat(scr));
- GETMEM(con2, sizeof(struct Condition));
- scr->text+=(brace=*scr->text==CHAR_OPEN_BRACE);
- con2->bracetext=scr->text;
- con2->braceprg=scr->prg;
- con2->check=NULL;
- if(scr->compiling)
- COMPILE(COMP_START_OF_BLOCK);
- CALL(Script(scr, val, SCR_DO|(brace?SCR_BRACE:0), con2));
- FREE(con2);
- if(CheckIt(scr, val, control, &ret)) {
- CleanUp(scr, control, levels);
- return(ret);
- }
- break;
- case CMD_FOR:
- Eat(scr);
- scr->text++;
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_SEMICOLON, NULL));
-
- if(*scr->text!=CHAR_SEMICOLON) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON));
- } else
- scr->text++;
- GETMEM(con2, sizeof(struct Condition));
-
- con2->check=scr->text;
- con2->checkl=scr->prg;
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_SEMICOLON|CON_NUM, NULL));
-
- if(*scr->text!=CHAR_SEMICOLON) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON));
- } else
- scr->text++;
- con2->postexpr=scr->text;
- con2->postexprl=scr->prg;
-
- if(scr->compiling) {
- /* Do the last expression too!! */
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
- if(*scr->text!=CHAR_CLOSE_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON));
- } else
- scr->text++; /* pass the closing parenthesis! */
- val->val.val= TRUE; /* always compile everything! */
- }
- else {
- /*
- * Pass the last expression:
- */
- CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, FALSE));
- }
- if(!val->val.val) {
- /* We shouldn't enter the loop! Go to end of block:*/
- CALL(SkipStatement(scr));
- FREE(con2);
- } else {
- CALL(Eat(scr));
- scr->text+=(brace=*scr->text==CHAR_OPEN_BRACE);
- con2->bracetext=scr->text;
- con2->braceprg=scr->prg;
- if(scr->compiling)
- COMPILE(COMP_START_OF_BLOCK);
- CALL(Script(scr, val, (brace?SCR_BRACE:0)|SCR_FOR, con2));
- FREE(con2);
- if(CheckIt(scr, val, control, &ret)) {
- CleanUp(scr, control, levels);
- return(ret);
- }
- }
- break;
- case CMD_RESIZE:
- CALL(Resize(scr, val, control));
- break;
- } /* switch(keyword) */
- } /* if it wasn't a declaring keyword */
- } else {
- if(scr->compiling)
- COMPILESYMBOL(scr->buf);
- declare=FALSE;
- CALL(Expression(val, scr, CON_ACTION|CON_IDENT, ident));
- if(val->flags&FPL_STRING && !(val->flags&FPL_NOFREE) && val->val.str)
- /* If there was a string return, it should be freed and the
- string really held a string! */
- FREE(val->val.str);
- if(*scr->text!=CHAR_SEMICOLON) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON)); /* >warning< */
- } else
- scr->text++;
- }
- } /* switch (*scr->text) */
-
- if(!(control&(SCR_BRACE|SCR_SWITCH))) {
- if(scr->compiling)
- COMPILE(COMP_END_OF_BLOCK);
- if(control&SCR_LOOP) {
- CALL(Loop(scr, con, control, &brace));
- if(brace && !scr->compiling) {
- /* Yes! We should loop! */
- if(control&SCR_BRACE) {
- /* bring back the proper values */
- scr->varlevel++;
- scr->level++;
- AddLevel(scr); /* restart this level! */
- declare=TRUE;
- }
- scr->virprg=virprg;
- scr->virfile=virfile;
- continue;
- }
- val->flags=0;
- ret=FPL_OK;
- break; /* return to calling function */
- } else
- break;
- }
- } /* loop! */
-
- /*
- * Check for that FPLTAG_INTERPRET tag!
- */
- if(!ret && scr->interpret) {
- /* an alternative main program is specified */
- GETMEM(pass, sizeof(struct fplArgument));
- pass->ID=FNC_INTERPRET;
- text = scr->interpret;
- pass->argv=(void **)&text;
- pass->key=scr;
- CALL(functions(pass));
-
- CleanUp(scr, control, levels);
-
- /* we're done for this time, exit! */
- ret = FPL_EXIT_OK;
- }
-
- CleanUp(scr, control, levels);
- return(ret);
- }
-
- static ReturnCode INLINE
- Switch(struct Data *scr,
- struct Expr *val,
- short control,
- struct Condition *con)
- {
- ReturnCode ret;
- struct fplStr *string;
- long value;
- char strtype=FALSE;
- char breakout=FALSE;
-
- char end=FALSE; /* we have not found the end position */
-
- long bprg;
- char *btext;
- long bvirprg;
- char *bvirfile;
-
- long dprg=-1;
- char *dtext;
- long dvirprg;
- char *dvirfile;
-
- CALL(Eat(scr)); /* eat whitespace */
-
- /* Check the open parenthesis */
- if(scr->text[0]!=CHAR_OPEN_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES)); /* >warning< */
- } else
- scr->text++;
-
- /* Get expression, string or int, static or dynamic! */
- CALL(Expression(val, scr, CON_NORMAL, NULL));
-
- if(val->flags&FPL_STRING) {
- /* there was a string statement! */
- string = val->val.str;
- if(string)
- strtype=2;
- else
- strtype= 1;
-
- } else {
- /* there was an integer expression */
- value = val->val.val;
- }
-
- /* Check the close parenthesis */
- if(scr->text[0]!=CHAR_CLOSE_PAREN) {
- CALL(Warn(scr, FPLERR_MISSING_PARENTHESES)); /* >warning< */
- } else
- scr->text++;
-
- CALL(Eat(scr)); /* eat whitespace */
-
- /* Check the open brace */
- if(scr->text[0]!=CHAR_OPEN_BRACE) {
- CALL(Warn(scr, FPLERR_MISSING_BRACE)); /* >warning< */
- } else
- scr->text++;
-
- while(!(ret=Eat(scr))) {
- if(!Getword(scr->buf, scr)) {
- if(!strcmp("case", scr->buf)) {
- /* This is a valid case-line coming up! */
-
- /* Get expression, string or int! */
- CALL(Expression(val, scr, strtype?CON_STRING:CON_NUM, NULL));
- if(strtype) {
- /*
- * String comparison:
- */
- value = val->val.str?val->val.str->len:0;
-
- if(value == (string?string->len:0)) {
-
- if(value) {
- if(!memcmp(val->val.str->string, string->string, value)) {
- /* match! */
- breakout=TRUE;
- }
- } else
- breakout=TRUE;
- }
- if(!val->flags&FPL_NOFREE)
- FREE(val->val.str);
- if(breakout)
- break;
- else
- scr->text++; /* pass the ';' */
- } else {
- /*
- * Integer comparison:
- */
- if(val->val.val == value) {
- breakout = TRUE;
- break;
- } else
- scr->text++; /* pass the ';' */
- }
- } else if(!strcmp("default", scr->buf)) {
- /*
- * Store the default position to make it possible to return to if
- * necessary!
- */
-
- if(dprg>=0)
- return FPLERR_ILLEGAL_STATEMENT; /* dual 'default' specified! */
-
- dprg = scr->prg;
- dtext = scr->text;
- dvirprg = scr->virprg;
- dvirfile = scr->virfile;
-
- } else {
- /*
- * Pass the statement!
- */
- CALL(SkipStatement(scr));
- }
- } else {
- /* we didn't get any word */
- if(scr->text[0]==CHAR_CLOSE_BRACE) {
- /*
- * We hit the end without finding our 'case'! Return to the
- * 'default', if any! Store the position to be able to quickly
- * jump down to it again after the possible case-statement.
- */
-
- scr->text++; /* pass the closing brace */
- if(dprg<0)
- /* we didn't find any 'default' */
- break;
- bprg = scr->prg;
- btext = scr->text;
- bvirprg = scr->virprg;
- bvirfile = scr->virfile;
-
- end=TRUE; /* we have found the end! */
-
- scr->prg=dprg;
- scr->text=dtext;
- scr->virprg=dvirprg;
- scr->virfile=dvirfile;
- breakout = TRUE;
- break;
-
- } else {
- /*
- * Pass the statement!
- */
- CALL(SkipStatement(scr));
- }
- }
- }
- if(breakout) {
- /* we did break out on any of the 'case' or 'default' label lines,
- pass the colon!
- */
- /* CALL(Eat(scr)); eating whitespace shouldn't be necessary here */
-
- /* Check the colon */
- if(scr->text[0]!=CHAR_COLON) {
- CALL(Warn(scr, FPLERR_MISSING_COLON)); /* missing colon */
- } else
- scr->text++;
-
- /*
- * run this statement all the way until break or '}'!
- */
-
- CALL(Script(scr, val, SCR_SWITCH, con));
-
- if(!(val->flags&FPL_BRACE)) {
- /* we didn't run into the closing brace! */
-
- /*
- * Go to the end of the switch()-statement.
- */
- if(!end) {
- /* we'll have to search for it! */
- CALL(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, FALSE));
- } else {
- scr->prg=bprg;
- scr->text=btext;
- scr->virprg=dprg;
- scr->virfile=dvirfile;
- }
- }
-
- }
- return ret;
- }
-
- static ReturnCode INLINE
- Declare(struct Expr *val,
- struct Data *scr,
- struct Identifier *ident,
- long start) /* start flags */
- {
- ReturnCode ret;
- long flags=start;
- char *text;
- long prg;
- do {
- switch(ident->data.external.ID) {
- case CMD_EXPORT:
- flags|=CON_DECLEXP;
- break;
- case CMD_STRING:
- flags|=CON_DECLSTR;
- break;
- case CMD_INT:
- flags|=CON_DECLINT;
- if(ident->flags&FPL_SHORT_VARIABLE)
- flags|=CON_DECL16;
- else if(ident->flags&FPL_CHAR_VARIABLE)
- flags|=CON_DECL8;
- break;
- case CMD_VOID:
- flags|=CON_DECLVOID;
- break;
- case CMD_AUTO:
- case CMD_REGISTER:
- flags&=~(CON_DECLEXP|CON_DECLGLOB);
- break;
- case CMD_CONST:
- flags|=CON_DECLCONST;
- break;
- case CMD_STATIC:
- flags|=CON_DECLSTATIC;
- break;
- }
- if(scr->compiling && !(ident->flags&FPL_IGNORE))
- COMPILESYMBOL(scr->buf);
- text=scr->text;
- prg=scr->prg;
- CALL(Getword(scr->buf, scr));
- ret=GetIdentifier(scr, scr->buf, &ident);
- } while(!ret && ident->flags&FPL_KEYWORD_DECLARE);
-
- scr->text=text;
- scr->prg=prg;
-
- if(!(flags&CON_DECLARE))
- flags|=CON_DECLINT; /* integer declaration is default! */
-
- CALL(Expression(val, scr, CON_GROUNDLVL|flags, NULL));
- if(*scr->text!=CHAR_SEMICOLON &&
- (!(val->flags&FPL_DEFUNCTION) || *scr->text!=CHAR_CLOSE_BRACE)) {
- CALL(Warn(scr, FPLERR_MISSING_SEMICOLON)); /* >warning< */
- } else
- scr->text++;
- return(FPL_OK);
- }
-
-
-
- /**********************************************************************
- *
- * Resize()
- *
- * This function resizes a variable array to the new given size.
- *
- *****/
-
- static ReturnCode INLINE Resize(struct Data *scr, struct Expr *val, char control)
- {
- char num=0; /* number of dimensions */
- long *dims; /* dimension array */
- char i; /* counter to max MAX_DIMS */
- int size, min;
- void *tempvars;
- struct fplVariable *var;
- struct Identifier *ident;
- ReturnCode ret;
- CALL(Getword(scr->buf, scr));
- CALL(GetIdentifier(scr, scr->buf, &ident));
- var=&ident->data.variable;
-
- if(!(ident->flags&FPL_VARIABLE) || !var->num) {
- CALL(Warn(scr, FPLERR_ILLEGAL_RESIZE));
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE));
- }
-
- if(scr->compiling)
- COMPILESYMBOL(scr->buf);
- Eat(scr);
- GETMEM(dims, MAX_DIMS*sizeof(long));
-
- do {
- if(*scr->text!=CHAR_OPEN_BRACKET) {
- CALL(Warn(scr, FPLERR_MISSING_BRACKET)); /* >warning< */
- } else
- scr->text++; /* pass the open bracket */
- /* eval the expression: */
- CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
- if(*scr->text++!=CHAR_CLOSE_BRACKET)
- /* no close bracket means error */
- return(FPLERR_MISSING_BRACKET); /* missing bracket */
- else if(val->val.val<(control&CON_DECLARE?1:0))
- /* illegal result of the expression */
- return(FPLERR_ILLEGAL_ARRAY);
-
- dims[num++]=val->val.val; /* Add another dimension */
- if(num==MAX_DIMS) {
- /* if we try to declare too many dimensions... */
- CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
-
- /* Get to the end of this absurd resize! */
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, !(*scr->text==CHAR_SEMICOLON)));
- break;
- }
- /*
- * Go on as long there are brackets,
- */
- } while(*scr->text==CHAR_OPEN_BRACKET);
-
- size=dims[0]; /* array size */
- for(i=1; i<num; i++)
- size*=dims[i];
-
- min=MIN(size, var->size); /* number of variables to copy! */
-
- GETMEM(tempvars, size * sizeof(void *)); /* data adjust! */
- memcpy(tempvars, var->var.str, min * sizeof(void *));
- if(size>var->size)
- /*
- * If we create a few more than before, empty that data!
- */
- memset((char *)tempvars+var->size*sizeof(void *), 0,
- (size-var->size)*sizeof(void *));
-
- if(ident->flags&FPL_STRING_VARIABLE)
- for(i=min; i<var->size; i++) {
- if(var->var.str[i])
- FREE(var->var.str[i]);
- }
-
- FREE(var->var.val);
- var->var.val= tempvars;
-
- var->size= size;
- FREE(var->dims);
- GETMEM(var->dims, num * sizeof(long));
- memcpy(var->dims, dims, num * sizeof(long));
-
- FREE(dims);
- return(FPL_OK);
- }
-
-
- /************************************************************************
- *
- * int GetEnd(struct Data *, char, char, char)
- *
- * Makes the current position to be the one right after the character
- * you wanna search for.
- *
- * Returns error code.
- *
- *****/
-
- ReturnCode
- GetEnd(struct Data *scr, /* giant script structure */
- char leta, /* what character you do wanna find */
- char motsats, /* the opposite character do the one above */
- char outside) /* TRUE/FALSE if outside an opposite version */
- {
- ReturnCode ret;
- char quot=FALSE, find=1-outside;
- long junk; /* only for the ReturnChar() function */
- long prg=scr->prg;
- char *text=scr->text;
- char check;
- if(scr->compiling)
- COMPILE(COMP_ERROR);
- while(scr->prg<=scr->prog->lines) {
- check=*scr->text;
- if(check==leta) {
- scr->text++;
- if(!quot && !--find)
- return(FPL_OK);
- } else if(check==motsats) {
- if(!quot)
- find++;
- scr->text++;
- } else if(check==CHAR_QUOTATION_MARK) {
- scr->text++;
- if(GetEnd(scr, CHAR_QUOTATION_MARK, (char)255, FALSE))
- return(FPLERR_SYNTAX_ERROR); /* missing quotation mark */
- } else if(check==CHAR_APOSTROPHE && leta!=CHAR_QUOTATION_MARK) {
- scr->text++;
- CALL(ReturnChar(scr, &junk, FALSE));
- if(CHAR_APOSTROPHE!=*scr->text++)
- return(FPLERR_MISSING_APOSTROPHE);
- } else if(check==CHAR_ASCII_ZERO) {
- CALL(Newline(scr));
- } else if(leta==CHAR_QUOTATION_MARK && check == CHAR_BACKSLASH) {
- CALL(ReturnChar(scr, &junk, TRUE));
- } else {
- if(check==CHAR_NEWLINE)
- scr->virprg++;
- scr->text++;
- if(leta!=CHAR_QUOTATION_MARK && Eat(scr))
- /* we only call Eat() if this is *not* a string passing! */
- break;
- }
- }
- scr->text=text;
- scr->prg=prg;
- return(FPLERR_MISSING_PARENTHESES);
- }
-
- /**********************************************************************
- *
- * Getword()
- *
- * Store next word in a buffer. Returns error code!
- *
- *******/
-
- ReturnCode Getword(char *buffer, struct Data *scr)
- {
- ReturnCode ret;
- char len=0;
- if(ret=Eat(scr))
- ;
- else if(!ALPHA(*scr->text))
- ret=FPLERR_SYNTAX_ERROR; /* non-alpha char found where alpha is supposed */
- else
- do {
- if(len<IDENTIFIER_LEN) {
- /*
- * With the length check above, we can use identifiers with
- * _any_ length. There are only IDENTIFIER_LEN number of
- * significant characters!
- *
- */
- len++;
- *buffer++=*scr->text++;
- }
- } while(ALPHANUM(*scr->text));
- *buffer=0;
- return(ret);
- }
-
- /**********************************************************************
- *
- * int Eatcomment(struct Data *);
- *
- * Jumps to the end of the comment we're standing on.
- *
- *******/
-
- static ReturnCode INLINE Eatcomment(struct Data *scr)
- {
- ReturnCode ret;
- long nums=0;
- scr->text+=2;
- while(scr->prg<=scr->prog->lines) {
- switch(scr->text[0]) {
- case CHAR_MULTIPLY:
- if(scr->text[1]==CHAR_DIVIDE) {
- scr->text+=2;
- if(nums--)
- break;
- return(FPL_OK);
- } else
- scr->text++;
- break;
- case CHAR_ASCII_ZERO:
- CALL(Newline(scr));
- break;
- case CHAR_NEWLINE:
- scr->text++;
- scr->virprg++; /* stepped down another virutal line! */
- /*
- * Place to debug-hook!
- */
- if(scr->newline_hook) {
- CALL(InterfaceCall(scr, scr, scr->newline_hook));
- }
- break;
- case CHAR_DIVIDE:
- if(scr->flags&FPLDATA_NESTED_COMMENTS && scr->text[1]==CHAR_MULTIPLY) {
- nums++;
- scr->text+=2;
- break;
- }
- default:
- scr->text++;
- break;
- }
- }
- return(FPLERR_UNBALANCED_COMMENT);
- }
-
- /**********************************************************************
- *
- * int Eat(struct Data *);
- *
- * This eats all whitespaces, new lines and comments
- *
- * Returns error code.
- *
- *******/
-
- ReturnCode Eat(struct Data *scr)
- {
- ReturnCode ret;
- char new=0;
- while(1) {
- switch(*scr->text) {
- case CHAR_NEWLINE:
- scr->text++;
- scr->virprg++; /* stepped down another virutal line! */
- /*
- * Place to debug-hook!
- */
- if(scr->newline_hook) {
- CALL(InterfaceCall(scr, scr, scr->newline_hook));
- }
- new=1;
- break;
- case CHAR_ASCII_ZERO:
- CALL(Newline(scr));
- /* This really confuses our virtual line counter! */
- break;
- case CHAR_HASH:
- if(new) {
- /* This is the first 'real' character after a newline! That means
- this could be a valid #line-instruction! */
- scr->text++; /* pass the hash */
- if(!Getword(scr->buf, scr) && strcmp(scr->buf, "line")) {
- /* If there is a word here, it must be "line", or we skip
- the line! */
- while (*++scr->text!=CHAR_NEWLINE);
- break;
- }
- scr->virprg=Strtol(scr->text, 10, &scr->text); /* get number */
- Eat(scr); /* get whitespace */
- if(*scr->text==CHAR_QUOTATION_MARK) {
- /* we have a new virtual file name! */
- scr->virfile=scr->text++; /* just point to this text! */
- CALL(GetEnd(scr, CHAR_QUOTATION_MARK, 255, FALSE));
- Eat(scr);
- }
- } else
- return(FPL_OK);
- break;
- case CHAR_DIVIDE:
- if(scr->text[1]==CHAR_MULTIPLY) {
- CALL(Eatcomment(scr));
- } else if(scr->text[1]==CHAR_DIVIDE)
- while (*++scr->text && *scr->text!=CHAR_NEWLINE);
- else
- return(FPL_OK);
- break;
- default:
- if(!WSPACE(*scr->text))
- return(FPL_OK);
- scr->text++;
- break;
- }
- }
- }
-
- /*********************************************************************
- *
- * Newline()
- *
- * This routine gets called everytime the interpreter finds an ASCII
- * zero in the program. This is made like this for future version which
- * will be able to specify programs in several ways. (Not only the
- * array and continues memory alternatives!)
- *
- *****/
-
- ReturnCode Newline(struct Data *scr)
- {
- if(scr->prg<scr->prog->lines) {
- scr->text=(&scr->prog->program)[scr->prg++];
- return(FPL_OK);
- } else
- return(FPLERR_UNEXPECTED_END);
- }
-
- /**********************************************************************
- *
- * char CheckIt()
- *
- * Returns wether we should return from this Script().
- *
- *****/
-
- static char REGARGS
- CheckIt(struct Data *scr, /* major script structure */
- struct Expr *val, /* result structure */
- short control, /* control defines */
- ReturnCode *ret) /* return code pointer */
- {
- if(val->flags&FPL_BREAK) {
- /*
- * A `break' was hit inside that Script() invoke.
- */
- if(control&SCR_LOOP) {
- if(control&SCR_BRACE) {
- /*
- * If we're inside braces, search for the close brace!
- */
- if(*ret=GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, FALSE))
- return((char)*ret);
- }
- if(control&SCR_DO) {
- /*
- * We're inside a do-statement! We must pass the ending "while"
- * before returning! We do it the easy way: look for the closing
- * parenthesis!
- */
- if(*ret=GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE))
- return((char)*ret);
- else if(*ret = Eat(scr))
- return((char)*ret);
- else if(scr->text[0] != CHAR_SEMICOLON) {
- if(*ret = Warn(scr, FPLERR_MISSING_SEMICOLON))
- return((char)*ret);
- } else
- scr->text++; /* pass the semicolon */
- }
- if(--val->val.val<1)
- val->flags&=~FPL_BREAK; /* clear the break bit! */
- return(TRUE);
- } else if(!(control&SCR_FUNCTION))
- return(TRUE);
- else if(val->val.val<2) {
- val->flags&=~FPL_BREAK; /* clear the break bit! */
- return(FALSE); /* no more break! */
- }
- *ret=FPLERR_ILLEGAL_BREAK;
- return(TRUE);
- } else if(val->flags&FPL_RETURN)
- /* The FPL function did end in a return() */
- return(TRUE);
- else if(val->flags&FPL_CONTINUE) {
- if(control&SCR_LOOP) {
- if(control&SCR_BRACE) {
- /* If we're inside braces, search for the close brace */
- if(*ret=GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, FALSE))
- return((char)*ret);
- scr->text--; /* move one step back to stand on the close brace */
- return(FALSE);
- }
- } else
- /* this is not a looping block, break out of it! */
- return(TRUE);
- }
- return(FALSE);
- }
-
- /**********************************************************************
- *
- * CleanUp()
- *
- * Deletes/frees all local variable information.
- *
- *******/
-
- void
- CleanUp(struct Data *scr,
- long control,
- long levels)
- {
- if(control&(SCR_BRACE|SCR_FUNCTION)) {
- DelLocalVar(scr, &scr->locals);
- scr->varlevel--;
- scr->level=levels; /* new variable amplitude */
- }
- }
-
-
- /**********************************************************************
- *
- * Loop()
- *
- * This function is called at the end of a block, however the block was
- * started (brace or not brace).
- *
- *******/
-
- static ReturnCode REGARGS
- Loop(struct Data *scr,
- struct Condition *con,
- short control,
- char *cont) /* store TRUE or FALSE if loop or not */
- {
- ReturnCode ret = FPL_OK;
- char *temptext=scr->text; /* store current position */
- long temprg=scr->prg;
- struct Expr val;
-
- /*
- * First check if the block just parsed begun with a while() or for()
- * or perhaps a do in which we know the statment position!
- */
-
- if((control&SCR_WHILE ||
- control&SCR_FOR ||
- (control&SCR_DO && con->check)) &&
- !scr->compiling) { /* not when compiling! */
- if(control&SCR_FOR) { /* check if the pre keyword was for() */
- scr->text=con->postexpr;/* perform the post expression */
- scr->prg=con->postexprl;
- CALL(Expression(&val, scr, CON_GROUNDLVL|CON_PAREN, NULL));
- }
- /*
- * Do the condition check. The only statement if it was a while() or
- * do while or the second statement if it was a for().
- *
- * If it was a for() as pre statement, the statement could contain
- * nothing but a semicolon and then equals TRUE.
- */
- scr->text=con->check;
- scr->prg=con->checkl;
- CALL(Expression(&val, scr, CON_GROUNDLVL|
- (control&SCR_FOR?CON_SEMICOLON:0)|CON_NUM, NULL));
-
- if(val.val.val) { /* the result of the condition was true */
- scr->text=con->bracetext; /* return to the open brace */
- scr->prg=con->braceprg;
- *cont=TRUE;
- return(FPL_OK);
- }
- }
-
- if(control&SCR_DO) {
- /* This a do while end. */
-
- if(!con->check) {
- /*
- * We *DON'T* know the condition position. We have to scan forward
- * to get it!
- */
- if(*scr->text==CHAR_CLOSE_BRACE)
- /* pass the close brace */
- scr->text++;
- if(ret=Getword(scr->buf, scr))
- ;
- else if(strcmp(scr->buf, "while"))
- ret=FPLERR_MISSING_WHILE; /* missing 'while' after do-while statement */
- else if(ret=Eat(scr))
- ;
- else if(*scr->text++!=CHAR_OPEN_PAREN)
- ret=FPLERR_MISSING_PARENTHESES; /* >warning< */
- else {
- con->check=scr->text;
- con->checkl=scr->prg;
- if(scr->compiling)
- COMPILE(COMP_START_OF_EXPR);
- if(ret=Expression(&val, scr, CON_GROUNDLVL|CON_NUM, NULL))
- ;
- else if(*scr->text++!=CHAR_CLOSE_PAREN)
- ret=FPLERR_MISSING_PARENTHESES; /* >warning< */
- else if(scr->compiling)
- return(FPL_OK);
- }
- if(ret)
- return(ret);
- }
- if(!val.val.val || scr->compiling) {
- /*
- * If we had the check point up there and the condition equaled
- * FALSE. Now we have to pass the the while keyword following the
- * close brace.
- */
- scr->text=temptext;
- scr->prg=temprg;
-
- if(*scr->text==CHAR_CLOSE_BRACE)
- /* pass the close brace */
- scr->text++;
-
- if(Getword(scr->buf, scr) || strcmp("while", scr->buf))
- ret=FPLERR_MISSING_WHILE; /* missing 'while' after do-while statement */
- else if(ret=GetEnd(scr, CHAR_SEMICOLON, (char)255, FALSE))
- ;
- if(ret)
- return(ret);
- } else {
- /* go to the open brace */
- scr->text=con->bracetext;
- scr->prg=con->braceprg;
- *cont=TRUE;
- return(FPL_OK);
- }
- }
-
- /*
- * The condition check has failed!
- */
-
- *cont=FALSE;
-
- if(!(control&SCR_DO)) {
- /* it's not a do-while loop */
-
- scr->text=temptext;
- scr->prg=temprg;
-
- Eat(scr);
-
- if(control&SCR_BRACE && *scr->text==CHAR_CLOSE_BRACE)
- /* pass the close brace */
- scr->text++;
- }
-
- return(ret);
- }
-
- /**********************************************************************
- *
- * ReturnCode SkipStatement();
- *
- * This function should pass one statement. Statements starting with
- * "for", "do", "while" or "if" really can be meesy and in such cases
- * this function recurse extensively!!!
- *
- ******/
-
- static ReturnCode REGARGS
- SkipStatement(struct Data *scr)
- {
- ReturnCode ret;
- struct Identifier *ident;
- CALL(Eat(scr));
-
- if(scr->compiling)
- COMPILE(COMP_ERROR);
-
- if(*scr->text==CHAR_SEMICOLON)
- scr->text++;
- else if(*scr->text==CHAR_OPEN_BRACE) {
- CALL(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, TRUE));
- } else {
- /*
- * Much more trouble this way:
- */
-
- char *t;
- long p;
-
- ret = Getword(scr->buf, scr);
- if(!ret) {
- GetIdentifier(scr, scr->buf, &ident);
- switch(ident?ident->data.external.ID:0) {
- case CMD_IF:
- case CMD_WHILE:
- Eat(scr);
- CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE));
- CALL(SkipStatement(scr));
-
- t=scr->text;
- p=scr->prg;
-
- Getword(scr->buf, scr);
-
- if(!strcmp("else", scr->buf)) {
- CALL(SkipStatement(scr));
- } else {
- /*
- * Restore pointers.
- */
- scr->text=t;
- scr->prg=p;
- }
- break;
- case CMD_FOR:
- Eat(scr);
- /* Now we must stand on an open parenthesis */
- CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE));
- CALL(SkipStatement(scr));
- break;
- case CMD_DO:
- Eat(scr);
- CALL(SkipStatement(scr));
-
- /*
- * The next semicolon must be the one after the
- * following `while' keyword!
- */
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE));
- break;
- default:
- ret=TRUE;
- }
- }
- if(ret) {
- /*
- * This statement ends at the next semicolon
- */
- CALL(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE));
- }
- }
- return(FPL_OK);
- }
-
- #ifdef UNIX
- long InterfaceCall(struct Data *scr,
- void *arg,
- long (*func)(void *))
- {
- return func(arg);
- }
- #endif
-